#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
数据管理器
负责状态数据的存储与读取
"""

import os
import json
import logging
import tempfile
import shutil
from typing import Dict, Any, Optional
from datetime import datetime

logger = logging.getLogger(__name__)

class StateRecorder:
    """
    状态记录器，负责保存和恢复操作状态
    """
    
    def __init__(self, state_dir: str):
        """
        初始化状态记录器
        
        Args:
            state_dir: 状态文件存储目录
        """
        self.state_dir = state_dir
        os.makedirs(state_dir, exist_ok=True)
    
    def load_state(self, user_id: str) -> Dict[str, Any]:
        """
        加载用户状态信息
        
        Args:
            user_id: 用户账号
            
        Returns:
            Dict: 当前进度字典结构
        """
        state_file = self._get_state_file_path(user_id)
        
        # 如果状态文件不存在，返回初始状态
        if not os.path.exists(state_file):
            logger.info(f"用户 {user_id} 的状态文件不存在，使用初始状态")
            return self._create_initial_state()
        
        try:
            with open(state_file, 'r', encoding='utf-8') as f:
                state = json.load(f)
                logger.info(f"成功加载用户 {user_id} 的状态")
                return state
        except Exception as e:
            logger.error(f"加载状态文件失败: {e}，使用初始状态")
            return self._create_initial_state()
    
    def save_state(self, user_id: str, operation_log: Dict[str, Any]) -> bool:
        """
        保存用户状态信息
        
        Args:
            user_id: 用户账号
            operation_log: 操作日志
            
        Returns:
            bool: 保存是否成功
        """
        state_file = self._get_state_file_path(user_id)
        
        try:
            # 加载当前状态（如果存在）
            current_state = self.load_state(user_id)
            
            # 更新状态
            current_state = self._update_state(current_state, operation_log)
            
            # 创建临时文件
            with tempfile.NamedTemporaryFile(delete=False, mode='w', encoding='utf-8') as temp_file:
                # 写入更新后的状态
                json.dump(current_state, temp_file, ensure_ascii=False, indent=2)
                temp_file_path = temp_file.name
            
            # 验证JSON文件完整性
            try:
                with open(temp_file_path, 'r', encoding='utf-8') as f:
                    json.load(f)
            except Exception as e:
                logger.error(f"生成的状态文件无效: {e}")
                os.unlink(temp_file_path)
                return False
            
            # 安全地替换原有状态文件
            try:
                # 如果原文件存在，先备份
                if os.path.exists(state_file):
                    backup_file = f"{state_file}.bak"
                    shutil.copy2(state_file, backup_file)
                
                # 移动临时文件到正式位置
                shutil.move(temp_file_path, state_file)
                
                # 成功后删除备份
                if os.path.exists(f"{state_file}.bak"):
                    os.unlink(f"{state_file}.bak")
                
                logger.info(f"成功保存用户 {user_id} 的状态")
                return True
            except Exception as e:
                logger.error(f"替换状态文件失败: {e}")
                # 尝试恢复备份
                if os.path.exists(f"{state_file}.bak"):
                    shutil.copy2(f"{state_file}.bak", state_file)
                return False
                
        except Exception as e:
            logger.error(f"保存状态文件失败: {e}")
            return False
    
    def _get_state_file_path(self, user_id: str) -> str:
        """
        获取状态文件路径
        
        Args:
            user_id: 用户账号
            
        Returns:
            str: 状态文件的完整路径
        """
        valid_user_id = self._sanitize_filename(user_id)
        return os.path.join(self.state_dir, f"{valid_user_id}.json")
    
    def _create_initial_state(self) -> Dict[str, Any]:
        """
        创建初始状态
        
        Returns:
            Dict: 初始状态结构
        """
        return {
            "current_cycle": 0,
            "completed_questions": [],
            "pending_actions": [],
            "has_pending_courses": True,
            "last_update": self._get_timestamp()
        }
    
    def _update_state(self, current_state: Dict[str, Any], operation_log: Dict[str, Any]) -> Dict[str, Any]:
        """
        根据操作日志更新状态
        
        Args:
            current_state: 当前状态
            operation_log: 操作日志
            
        Returns:
            Dict: 更新后的状态
        """
        # 更新最后更新时间
        current_state["last_update"] = self._get_timestamp()
        
        # 根据操作类型更新状态
        action = operation_log.get("action", "")
        
        if action == "选择题完成":
            # 记录完成的问题
            if "question_id" in operation_log.get("result", {}).get("operation", {}):
                q_id = operation_log["result"]["operation"]["question_id"]
                if q_id not in current_state["completed_questions"]:
                    current_state["completed_questions"].append(q_id)
            
        elif action == "填空题完成":
            # 记录完成的问题
            if "question_id" in operation_log.get("result", {}).get("operation", {}):
                q_id = operation_log["result"]["operation"]["question_id"]
                if q_id not in current_state["completed_questions"]:
                    current_state["completed_questions"].append(q_id)
            
        elif action == "评教完成":
            # 一个评教周期完成
            current_state["current_cycle"] += 1
            # 清空完成的问题列表，准备下一个评教
            current_state["completed_questions"] = []
            
        # 更新操作历史
        if "operation_history" not in current_state:
            current_state["operation_history"] = []
        
        # 添加到操作历史
        history_entry = {
            "action": action,
            "timestamp": self._get_timestamp(),
            "details": operation_log
        }
        current_state["operation_history"].append(history_entry)
        
        # 限制历史记录条数，防止文件过大
        if len(current_state["operation_history"]) > 100:
            current_state["operation_history"] = current_state["operation_history"][-100:]
        
        return current_state
    
    def _get_timestamp(self) -> str:
        """
        获取当前时间戳
        
        Returns:
            str: 格式化的时间戳
        """
        return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    def _sanitize_filename(self, filename: str) -> str:
        """
        清理文件名，确保安全
        
        Args:
            filename: 原始文件名
            
        Returns:
            str: 安全的文件名
        """
        # 替换不安全的字符
        invalid_chars = '<>:"/\\|?*'
        for char in invalid_chars:
            filename = filename.replace(char, '_')
        
        return filename 